package com.csii.user.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.csii.core.api.Result;
import com.csii.core.constant.CacheConstant;
import com.csii.core.constant.CommonConstant;
import com.csii.core.constant.PublishAndSubscribeConstant;
import com.csii.core.system.vo.LoginUser;
import com.csii.core.system.vo.SysUserCacheInfo;
import com.csii.core.util.PasswordUtil;
import com.csii.core.util.TenantContext;
import com.csii.core.util.UUIDGenerator;
import com.csii.core.util.oConvertUtils;
import com.csii.ldap.entity.GroupUser;
import com.csii.ldap.service.GroupUserService;
//import com.csii.service.PublishService;
import com.csii.user.entity.*;
import com.csii.user.mapper.*;
import com.csii.user.model.SysUserSysDepartModel;
import com.csii.user.service.ISysBaseAPI;
import com.csii.user.service.ISysRoleGroupService;
import com.csii.user.service.ISysRoleService;
import com.csii.user.service.ISysUserService;
import com.csii.user.vo.SysUserDepVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.NameAwareAttribute;
import org.springframework.ldap.query.LdapQueryBuilder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @Author: scott
 * @Date: 2018-12-20
 */
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    @Autowired
    private SysPermissionMapper sysPermissionMapper;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    private SysUserDepartMapper sysUserDepartMapper;
    @Autowired
    private ISysBaseAPI sysBaseAPI;
    @Autowired
    private SysDepartMapper sysDepartMapper;
    @Autowired
    private SysDepartRoleUserMapper departRoleUserMapper;
    @Autowired
    private SysDepartRoleMapper sysDepartRoleMapper;
    @Autowired
    private GroupUserService groupUserService;
    @Autowired
    private ISysRoleService iSysRoleService;
    //@Autowired
    //private PublishService publishService;
    @Autowired
    private ISysRoleGroupService sysRoleGroupService;

    @Value("${ldap.enable:true}")
    private Boolean ldapEnable;

    @Override
    @CacheEvict(value = {CacheConstant.SYS_USERS_CACHE}, allEntries = true)
    public Result<?> resetPassword(String username, String oldpassword, String newpassword, String confirmpassword) {
        SysUser user = baseMapper.getUserByName(username);
        if (!PasswordUtil.isMatch(user.getPassword(), oldpassword)) {
            return Result.error("旧密码输入错误!");
        }
        if (oConvertUtils.isEmpty(newpassword)) {
            return Result.error("新密码不允许为空!");
        }
        if (!newpassword.equals(confirmpassword)) {
            return Result.error("两次输入密码不一致!");
        }
        SysUser sysUser = new SysUser();
        sysUser.setPassword(new BCryptPasswordEncoder().encode(newpassword));

        if (ldapEnable) {
            //修改ldap服务器用户的密码
            changeGroupUserPwd(username, newpassword);
        }
        this.baseMapper.update(sysUser, new LambdaQueryWrapper<SysUser>().eq(SysUser::getId, user.getId()));
        return Result.ok("密码重置成功!");
    }

    @Override
    public void saveGroupUser(SysUser sysUser, String pwd, String selectedRoles) {
        if(!ldapEnable)
            return;
        GroupUser user = new GroupUser();
        user.setPhone(sysUser.getPhone());
        user.setEmail(sysUser.getEmail());
        user.setFullName(sysUser.getUsername());
        user.setPassword(pwd);
        user.setHomeDirectory("/home/users/" + sysUser.getUsername());
        user.setUid(sysUser.getUsername());
        user.setGidNumber(504);
        user.setUidNumber(999);
        user.setDepartment("Default");
        user.setLastName(StrUtil.isNotBlank(sysUser.getRealname()) ? sysUser.getRealname() : sysUser.getUsername());

        if (StrUtil.isNotBlank(selectedRoles)) {
            // 获取所有的角色编码
            List<String> list = iSysRoleService.listObjs(new LambdaQueryWrapper<SysRole>().select(SysRole::getRoleCode)
                    .in(SysRole::getId, selectedRoles.split(",")).orderByDesc(SysRole::getCreateTime), Object::toString);
            String desc = StrUtil.join(",", list);
            user.setDescription(desc);
        }

        groupUserService.save(user);
    }

    @Override
    public void changeGroupUserPwd(String userName, String password) {
        if(!ldapEnable)
            return;
        // 根据username查询用户信息
        Optional<GroupUser> groupUser = groupUserService.findOne(
                LdapQueryBuilder.query().where("cn").is(userName));
        if (groupUser.isPresent()) {
            GroupUser user = groupUser.get();
            user.setPassword(password);
            groupUserService.save(user);
        }
    }

    @Override
    public void delGroupUser(String userName) {

    }

    @Override
    public void updateGroupUser(SysUser user, String roleIds) {

    }

    @Override
    public void addOrDelRoleForGroupUser(String userId, String roleId, Boolean add) {

    }

    @Override
    @CacheEvict(value = {CacheConstant.SYS_USERS_CACHE}, allEntries = true)
    public Result<?> changePassword(SysUser sysUser) {
        if (ldapEnable) {
            //修改ldap服务器用户的密码
            changeGroupUserPwd(sysUser.getUsername(), sysUser.getPassword());
        }
        sysUser.setPassword(new BCryptPasswordEncoder().encode(sysUser.getPassword()));
        this.baseMapper.updateById(sysUser);
        return Result.ok("密码修改成功!");
    }

    @Override
    @CacheEvict(value = {CacheConstant.SYS_USERS_CACHE}, allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteUser(String userId) {
        if (ldapEnable) {
            // 删除ldap用户
            delGroupUser(baseMapper.selectById(userId).getUsername());
        }
        //1.删除用户
        this.removeById(userId);
        return false;
    }

    @Override
    @CacheEvict(value = {CacheConstant.SYS_USERS_CACHE}, allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteBatchUsers(String userIds) {
        List<String> ids = Arrays.asList(userIds.split(","));
        List<SysUser> userList = baseMapper.selectBatchIds(ids);
        if (ldapEnable) {
            // 删除ldap服务器上的用户
            userList.forEach(user -> delGroupUser(user.getUsername()));
        }
        //1.删除用户
        this.removeByIds(ids);
        return false;
    }

    @Override
    public SysUser getUserByName(String username) {
        return baseMapper.getUserByName(username);
    }

    @Override
    @Transactional
    public void addUserWithRole(SysUser user,  String roles,String roleGroups) {
        this.save(user);
        // 查询角色id代表的角色名
        List<SysRole> roleList = null;
        if (oConvertUtils.isNotEmpty(roles)) {
            String[] arr = roles.split(",");
            roleList = iSysRoleService.list(new LambdaQueryWrapper<SysRole>().in(SysRole::getId, arr));
            for (String roleId : arr) {
                SysUserRole userRole = new SysUserRole(user.getId(), roleId);
                sysUserRoleMapper.insert(userRole);
            }
        }
        List<SysRoleGroup> groupList = null;
        if (oConvertUtils.isNotEmpty(roleGroups)) {
            String[] arr = roleGroups.split(",");
            for (String roleId : arr) {
                SysUserRole userRole = new SysUserRole(user.getId(), null);
                userRole.setRoleGroupId(roleId);
                sysUserRoleMapper.insert(userRole);
            }
        }
        // 发布消息
        user.setRoleList(roleList);
        //publishService.publish(PublishAndSubscribeConstant.USER_INFO_ADD_SYNC, user);
    }

    @Override
    @Transactional
    public void addUserWithRole(SysUser user, String roles) {
        addUserWithRole(user,roles,null);
    }

    @Override
    @CacheEvict(value = {CacheConstant.SYS_USERS_CACHE}, allEntries = true)
    @Transactional
    public void editUserWithRole(SysUser user, String roles,String roleGroups) {
        this.updateById(user);
        //先删后加
        sysUserRoleMapper.delete(new QueryWrapper<SysUserRole>().lambda().eq(SysUserRole::getUserId, user.getId()));
        // 查询角色id代表的角色名
        List<SysRole> roleList = null;
        if (oConvertUtils.isNotEmpty(roles)) {
            String[] arr = roles.split(",");
            roleList = iSysRoleService.list(new LambdaQueryWrapper<SysRole>().in(SysRole::getId, arr));
            for (String roleId : arr) {
                SysUserRole userRole = new SysUserRole(user.getId(), roleId);
                sysUserRoleMapper.insert(userRole);
            }
        }
        if (oConvertUtils.isNotEmpty(roleGroups)) {
            String[] arr = roleGroups.split(",");
            for (String roleId : arr) {
                SysUserRole userRole = new SysUserRole(user.getId(), null);
                userRole.setRoleGroupId(roleId);
                sysUserRoleMapper.insert(userRole);
            }
        }
        //发布消息
        List<SysUser> sysUserList = new ArrayList<>();
        user.setRoleList(roleList);
        sysUserList.add(user);
        //publishService.publish(PublishAndSubscribeConstant.USER_INFO_UPDATE_SYNC, sysUserList);
    }

    @Override
    public List<String> getRole(String username) {
        return sysUserRoleMapper.getRoleByUserName(username);
    }

    /**
     * 通过用户名获取用户角色集合
     *
     * @param username 用户名
     * @return 角色集合
     */
    @Override
    public Set<String> getUserRolesSet(String username) {
        // 查询用户拥有的角色集合
        List<String> roles = sysUserRoleMapper.getRoleByUserName(username);
        log.info("-------通过数据库读取用户拥有的角色Rules------username： " + username + ",Roles size: " + (roles == null ? 0 : roles.size()));
        return new HashSet<>(roles);
    }

    /**
     * 通过用户名获取用户权限集合
     *
     * @param username 用户名
     * @return 权限集合
     */
    @Override
    public Set<String> getUserPermissionsSet(String username) {
        Set<String> permissionSet = new HashSet<>();
        List<SysPermission> permissionList = sysPermissionMapper.queryByUser(username);
        for (SysPermission po : permissionList) {
//			// TODO URL规则有问题？
//			if (oConvertUtils.isNotEmpty(po.getUrl())) {
//				permissionSet.add(po.getUrl());
//			}
            if (oConvertUtils.isNotEmpty(po.getPerms())) {
                permissionSet.add(po.getPerms());
            }
        }
        log.info("-------通过数据库读取用户拥有的权限Perms------username： " + username + ",Perms size: " + permissionSet.size());
        return permissionSet;
    }

    @Override
    public SysUserCacheInfo getCacheUser(String username) {
        SysUserCacheInfo info = new SysUserCacheInfo();
        info.setOneDepart(true);
        LoginUser user = sysBaseAPI.getUserByName(username);
        if (user != null) {
            info.setSysUserName(user.getUsername());
            info.setRealName(user.getRealname());
            info.setSysOrgCode(user.getOrgCode());
            info.setPhone(user.getPhone());
            info.setEmail(user.getEmail());
            info.setAddress(user.getAddress());
            info.setTel(user.getTelephone());
            info.setSysOrgName(user.getOrgName());
            info.setUserPost(user.getPostName());
            info.setUserWorkNum(user.getWorkNum());
            info.setAvatar(user.getAvatar());
            info.setSex(user.getSex());
            //多部门支持in查询
            List<SysDepart> list = sysDepartMapper.queryUserDeparts(user.getId());
            List<String> sysMultiOrgCode = new ArrayList<String>();
            if (list == null || list.size() == 0) {
                //当前用户无部门
                //sysMultiOrgCode.add("0");
            } else if (list.size() == 1) {
                sysMultiOrgCode.add(list.get(0).getOrgCode());
            } else {
                info.setOneDepart(false);
                for (SysDepart dpt : list) {
                    sysMultiOrgCode.add(dpt.getOrgCode());
                }
            }
            info.setSysMultiOrgCode(sysMultiOrgCode);
        }

        return info;
    }

    // 根据部门Id查询
    @Override
    public IPage<SysUser> getUserByDepId(Page<SysUser> page, String departId, String username) {
        return baseMapper.getUserByDepId(page, departId, username);
    }

    @Override
    public IPage<SysUser> getUserByDepIds(Page<SysUser> page, List<String> departIds, String username) {
        return baseMapper.getUserByDepIds(page, departIds, username);
    }

    @Override
    public Map<String, String> getDepNamesByUserIds(List<String> userIds) {
        List<SysUserDepVo> list = this.baseMapper.getDepNamesByUserIds(userIds);

        Map<String, String> res = new HashMap<String, String>();
        list.forEach(item -> {
                    if (res.get(item.getUserId()) == null) {
                        res.put(item.getUserId(), item.getDepartName());
                    } else {
                        res.put(item.getUserId(), res.get(item.getUserId()) + "," + item.getDepartName());
                    }
                }
        );
        return res;
    }

    @Override
    public IPage<SysUser> getUserByDepartIdAndQueryWrapper(Page<SysUser> page, String departId, QueryWrapper<SysUser> queryWrapper) {
        LambdaQueryWrapper<SysUser> lambdaQueryWrapper = queryWrapper.lambda();

        lambdaQueryWrapper.eq(SysUser::getDelFlag, "0");
        lambdaQueryWrapper.inSql(SysUser::getId, "SELECT user_id FROM sys_user_depart WHERE dep_id = '" + departId + "'");

        return baseMapper.selectPage(page, lambdaQueryWrapper);
    }

    @Override
    public IPage<SysUserSysDepartModel> queryUserByOrgCode(String orgCode, SysUser userParams, IPage page) {
        List<SysUserSysDepartModel> list = baseMapper.getUserByOrgCode(page, orgCode, userParams, TenantContext.getTenant());
        Integer total = baseMapper.getUserByOrgCodeTotal(orgCode, userParams, TenantContext.getTenant());

        IPage<SysUserSysDepartModel> result = new Page<>(page.getCurrent(), page.getSize(), total);
        result.setRecords(list);

        return result;
    }

    // 根据角色Id查询
    @Override
    public IPage<SysUser> getUserByRoleId(Page<SysUser> page, String roleId, String username) {
        return baseMapper.getUserByRoleId(page, roleId, username);
    }

    // 根据角色组Id查询
    @Override
    public IPage<SysUser> getUserByGroupId(Page<SysUser> page, String groupId, String username) {
        return baseMapper.getUserByRoleGroupId(page, groupId, username);
    }

    @Override
    @CacheEvict(value = {CacheConstant.SYS_USERS_CACHE}, key = "#username")
    public void updateUserDepart(String username, String orgCode) {
        baseMapper.updateUserDepart(username, orgCode);
    }


    @Override
    public SysUser getUserByPhone(String phone) {
        return baseMapper.getUserByPhone(phone);
    }


    @Override
    public SysUser getUserByEmail(String email) {
        return baseMapper.getUserByEmail(email);
    }

    @Override
    @Transactional
    public void addUserWithDepart(SysUser user, String selectedParts) {
//		this.save(user);  //保存角色的时候已经添加过一次了
        if (oConvertUtils.isNotEmpty(selectedParts)) {
            String[] arr = selectedParts.split(",");
            for (String deaprtId : arr) {
                SysUserDepart userDeaprt = new SysUserDepart(user.getId(), deaprtId);
                sysUserDepartMapper.insert(userDeaprt);
            }
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {CacheConstant.SYS_USERS_CACHE}, allEntries = true)
    public void editUserWithDepart(SysUser user, String departs) {
        this.updateById(user);  //更新角色的时候已经更新了一次了，可以再跟新一次
        String[] arr = {};
        if (oConvertUtils.isNotEmpty(departs)) {
            arr = departs.split(",");
        }
        //查询已关联部门
        List<SysUserDepart> userDepartList = sysUserDepartMapper.selectList(new QueryWrapper<SysUserDepart>().lambda().eq(SysUserDepart::getUserId, user.getId()));
        if (userDepartList != null && userDepartList.size() > 0) {
            for (SysUserDepart depart : userDepartList) {
                //修改已关联部门删除部门用户角色关系
                if (!Arrays.asList(arr).contains(depart.getDepId())) {
                    List<SysDepartRole> sysDepartRoleList = sysDepartRoleMapper.selectList(
                            new QueryWrapper<SysDepartRole>().lambda().eq(SysDepartRole::getDepartId, depart.getDepId()));
                    List<String> roleIds = sysDepartRoleList.stream().map(SysDepartRole::getId).collect(Collectors.toList());
                    if (roleIds != null && roleIds.size() > 0) {
                        departRoleUserMapper.delete(new QueryWrapper<SysDepartRoleUser>().lambda().eq(SysDepartRoleUser::getUserId, user.getId())
                                .in(SysDepartRoleUser::getDroleId, roleIds));
                    }
                }
            }
        }
        //先删后加
        sysUserDepartMapper.delete(new QueryWrapper<SysUserDepart>().lambda().eq(SysUserDepart::getUserId, user.getId()));
        if (oConvertUtils.isNotEmpty(departs)) {
            for (String departId : arr) {
                SysUserDepart userDepart = new SysUserDepart(user.getId(), departId);
                sysUserDepartMapper.insert(userDepart);
            }
        }
    }


    /**
     * 校验用户是否有效
     *
     * @param sysUser
     * @return
     */
    @Override
    public Result<?> checkUserIsEffective(SysUser sysUser) {
        Result<?> result = new Result<Object>();
        //情况1：根据用户信息查询，该用户不存在
        if (sysUser == null) {
            result.error500("该用户不存在，请注册");
            sysBaseAPI.addLog("用户登录失败，用户不存在！", CommonConstant.LOG_TYPE_1, null);
            return result;
        }
        //情况2：根据用户信息查询，该用户已注销
        //update-begin---author:王帅   Date:20200601  for：if条件永远为falsebug------------
        if (CommonConstant.DEL_FLAG_1.intValue() == sysUser.getDelFlag()) {
            //update-end---author:王帅   Date:20200601  for：if条件永远为falsebug------------
            sysBaseAPI.addLog("用户登录失败，用户名:" + sysUser.getUsername() + "已注销！", CommonConstant.LOG_TYPE_1, null);
            result.error500("该用户已注销");
            return result;
        }
        //情况3：根据用户信息查询，该用户已冻结
        if (CommonConstant.USER_FREEZE.equals(sysUser.getStatus())) {
            sysBaseAPI.addLog("用户登录失败，用户名:" + sysUser.getUsername() + "已冻结！", CommonConstant.LOG_TYPE_1, null);
            result.error500("该用户已冻结");
            return result;
        }
        return result;
    }

    @Override
    public List<SysUser> queryLogicDeleted() {
        return this.queryLogicDeleted(null);
    }

    @Override
    public List<SysUser> queryLogicDeleted(LambdaQueryWrapper<SysUser> wrapper) {
        if (wrapper == null) {
            wrapper = new LambdaQueryWrapper<>();
        }
        wrapper.eq(SysUser::getDelFlag, "1");
        return baseMapper.selectLogicDeleted(wrapper);
    }

    @Override
    public boolean revertLogicDeleted(List<String> userIds, SysUser updateEntity) {
        String ids = String.format("'%s'", String.join("','", userIds));
        return baseMapper.revertLogicDeleted(ids, updateEntity) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeLogicDeleted(List<String> userIds) {
        String ids = String.format("'%s'", String.join("','", userIds));
        // 1. 删除用户
        int line = baseMapper.deleteLogicDeleted(ids);
        // 2. 删除用户部门关系
        line += sysUserDepartMapper.delete(new LambdaQueryWrapper<SysUserDepart>().in(SysUserDepart::getUserId, userIds));
        //3. 删除用户角色关系
        line += sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getUserId, userIds));
        return line != 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateNullPhoneEmail() {
        baseMapper.updateNullByEmptyString("email");
        baseMapper.updateNullByEmptyString("phone");
        return true;
    }

    @Override
    public void saveThirdUser(SysUser sysUser) {
        //保存用户
        String userid = UUIDGenerator.generate();
        sysUser.setId(userid);
        baseMapper.insert(sysUser);
        //获取第三方角色
        SysRole sysRole = iSysRoleService.getOne(new LambdaQueryWrapper<SysRole>().eq(SysRole::getRoleCode, "third_role"));
        //保存用户角色
        SysUserRole userRole = new SysUserRole();
        userRole.setRoleId(sysRole.getId());
        userRole.setUserId(userid);
        sysUserRoleMapper.insert(userRole);
    }

    @Override
    public List<SysUser> queryByDepIds(List<String> departIds, String username) {
        return baseMapper.queryByDepIds(departIds, username);
    }
    @Override
    public SysUser selectOnByThirdId(String type, String thirdId) {
        return baseMapper.selectOne(Wrappers.lambdaQuery(SysUser.class).eq(true, SysUser::getThirdType, type).eq(true, SysUser::getThirdId, thirdId));
    }

    @Override
    public List<SysUser> getUserListAndRole(List<String> userIds) {
        return baseMapper.getUserListAndRole(userIds);
    }
    @Override
    public List<SysUser> getUserListAndGroup(List<String> userIds) {
        return baseMapper.getUserListAndGroup(userIds);
    }
    @Override
    public List<SysUser> queryUserByRoleCode(String roleCode) {
        return baseMapper.queryUserByRoleCode(roleCode);
    }

    @Override
    @CacheEvict(cacheNames= CacheConstant.SYS_USERS_CACHE, key="T(com.csii.core.util.TenantContext).getTenantDefaultString()+#username")
    public void valiUserCahce(String username) {
        log.info("清除用户缓存...");
    }
}
